"use client";

import { gameList } from "@/config/game";
import React, { useEffect, useRef, useState, useMemo } from "react";
import { useDragInertia } from "./useDragInertia";
import AnimatingGameImage, {
  type AnimatingGameImageRef,
  type GameImgData,
} from "./AnimatingGameImage";
import { useIsMobile } from "@/hooks/use-mobile";
import { useDebounceFn } from "ahooks";

const IMG_TOTAL = 24;
const ROW_MAX = 6;
const LINE_MAX = 4;

export default function PhotoboxCanvas() {
  const canvasRef = useRef<HTMLCanvasElement | null>(null);
  const ctxRef = useRef<CanvasRenderingContext2D | null>(null);
  const imgDataRef = useRef<GameImgData[]>([]);
  const [selectedImage, setSelectedImage] = useState<GameImgData | null>(null);
  const animationFrameRef = useRef<number | null>(null);
  const animatingImageRef = useRef<AnimatingGameImageRef | null>(null);
  const isMobile = useIsMobile();
  const loadingImagesRef = useRef<Set<HTMLImageElement>>(new Set());
  const dragStartPosRef = useRef<{ x: number; y: number } | null>(null);
  const lastWheelTimeRef = useRef<number>(0);
  const hasMovedRef = useRef<boolean>(false); // 是否发生了真正的拖拽

  const imgDimensions = useMemo(() => {
    if (typeof window === "undefined")
      return {
        width: 0,
        height: 0,
      };

    const windowHeight = isMobile
      ? Math.round(window.screen.height / 4)
      : Math.round(window.screen.height / 3);

    const windowWidth = windowHeight / 1.5;

    return {
      width: windowWidth,
      height: windowHeight,
    };
  }, [isMobile]);

  const imgWidth = imgDimensions.width;
  const imgHeight = imgDimensions.height;
  const imgMargin = useMemo(() => {
    return isMobile ? 50 : 150;
  }, [isMobile]);

  // 总宽高：横向/纵向排列的所有图片宽高+间隔之和（最后一张不需要右/下间隔）
  const TOTAL_WIDTH = ROW_MAX * (imgWidth + imgMargin) - imgMargin;
  const TOTAL_HEIGHT = LINE_MAX * (imgHeight + imgMargin) - imgMargin;

  // 初始化：获取上下文、设置尺寸、加载图片、绑定 resize
  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext("2d");
    if (!ctx) return;
    ctxRef.current = ctx;

    resizeCanvas();
    createImgData();

    const onResize = () => resizeCanvas();
    window.addEventListener("resize", onResize);

    return () => {
      window.removeEventListener("resize", onResize);
      // 清理正在加载的图片
      cleanupLoadingImages();
    };
  }, [imgWidth, imgHeight]);

  // 清理动画
  useEffect(() => {
    return () => {
      if (animationFrameRef.current) {
        cancelAnimationFrame(animationFrameRef.current);
      }
    };
  }, []);

  const resizeCanvas = () => {
    const canvas = canvasRef.current;
    const ctx = ctxRef.current;
    if (!canvas || !ctx) return;
    // 使用 CSS 控制视觉尺寸，用 DOM 尺寸作为真实绘制尺寸
    canvas.width = canvas.clientWidth;
    canvas.height = canvas.clientHeight;
    // 重绘一次（canvas 尺寸变化会清空图层）
    if (imgDataRef.current.length > 0) {
      drawAll();
    }
  };

  // 清理正在加载的图片
  const cleanupLoadingImages = () => {
    loadingImagesRef.current.forEach((img) => {
      img.onload = null;
      img.onerror = null;
    });
    loadingImagesRef.current.clear();
  };

  const { run: createImgData } = useDebounceFn(
    () => {
      // 清理之前正在加载的图片
      cleanupLoadingImages();

      // 清空画布
      const currentCanvas = canvasRef.current;
      const currentCtx = ctxRef.current;
      if (currentCanvas && currentCtx) {
        currentCtx.clearRect(0, 0, currentCanvas.width, currentCanvas.height);
      }

      imgDataRef.current = [];

      for (let i = 0; i < IMG_TOTAL; i++) {
        const colIndex = i % ROW_MAX;
        const lineIndex = Math.floor(i / ROW_MAX);
        const x = colIndex * (imgWidth + imgMargin);
        // 为偶数列（索引为奇数的列）添加50%图片高度的向下偏移,并整体向上移动100px
        const y =
          lineIndex * (imgHeight + imgMargin) +
          (colIndex % 2 === 1 ? imgHeight * 0.5 : 0) -
          200;

        // 先创建占位符数据
        const img = new Image();
        imgDataRef.current[i] = {
          img,
          x,
          y,
          gameData: gameList[i],
          index: i,
          opacity: 1,
          loaded: false,
        };

        loadingImagesRef.current.add(img);

        // 将图片放在 public/photos 下
        img.src = gameList[i].img;
        img.onload = () => {
          // 检查这个图片是否还在当前加载集合中
          if (!loadingImagesRef.current.has(img)) {
            return;
          }

          // 更新加载状态
          imgDataRef.current[i].loaded = true;

          // 初次加载也绘制一次,保证进入页面可见
          const currentCtx2 = ctxRef.current;
          const currentCanvas2 = canvasRef.current;
          if (currentCtx2 && currentCanvas2) {
            drawAll(); // 重新绘制所有图片，包括刚加载完成的
          }

          // 加载完成后从集合中移除
          loadingImagesRef.current.delete(img);
        };

        img.onerror = () => {
          loadingImagesRef.current.delete(img);
        };
      }

      // 初始绘制占位符
      const initialCtx = ctxRef.current;
      const initialCanvas = canvasRef.current;
      if (initialCtx && initialCanvas) {
        drawAll();
      }
    },
    { wait: 100 }
  );

  // 绘制带圆角的图片或占位符
  const drawImageWithRadius = (
    ctx: CanvasRenderingContext2D,
    img: HTMLImageElement,
    x: number,
    y: number,
    width: number,
    height: number,
    opacity: number,
    radius: number,
    loaded: boolean = true
  ) => {
    ctx.save();
    // 设置透明度
    ctx.globalAlpha = opacity;
    // 创建圆角矩形路径
    ctx.beginPath();
    ctx.roundRect(x, y, width, height, radius);
    ctx.clip();

    if (loaded) {
      // 绘制图片
      ctx.drawImage(img, x, y, width, height);
    } else {
      // 绘制占位符
      // 填充背景
      ctx.fillStyle = "transparent";
      ctx.fill();

      // 绘制边框
      ctx.strokeStyle = "#e0e0e0";
      ctx.lineWidth = 4;
      ctx.stroke();

      // 绘制"加载中"文字
      ctx.globalAlpha = opacity * 0.7;
      // ctx.fillStyle = "#999";
      ctx.font = `${Math.min(width, height) * 0.12}px Arial`;
      ctx.textAlign = "center";
      ctx.textBaseline = "middle";
      ctx.fillText("拼命加载ing···", x + width / 2, y + height / 2);
    }

    ctx.restore();
  };

  const drawAllFlush = () => {
    const canvas = canvasRef.current;
    const ctx = ctxRef.current;
    if (!canvas || !ctx) return;
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    imgDataRef.current.forEach((d) => {
      drawImageWithRadius(
        ctx,
        d.img,
        d.x,
        d.y,
        imgWidth,
        imgHeight,
        d.opacity,
        8,
        d.loaded
      );
    });
  };

  const { run: drawAll } = useDebounceFn(drawAllFlush, { wait: 100 });

  const moveImages = (dx: number, dy: number) => {
    const canvas = canvasRef.current;
    const ctx = ctxRef.current;
    if (!canvas || !ctx) return;

    ctx.clearRect(0, 0, canvas.width, canvas.height);

    imgDataRef.current.forEach((img) => {
      img.x += dx;
      if (img.x > TOTAL_WIDTH - imgWidth) {
        img.x -= TOTAL_WIDTH + imgMargin;
      }
      if (img.x < -imgWidth) {
        img.x += TOTAL_WIDTH + imgMargin;
      }

      img.y += dy;
      if (img.y > TOTAL_HEIGHT - imgHeight) {
        img.y -= TOTAL_HEIGHT + imgMargin;
      }
      if (img.y < -imgHeight) {
        img.y += TOTAL_HEIGHT + imgMargin;
      }

      drawImageWithRadius(
        ctx,
        img.img,
        img.x,
        img.y,
        imgWidth,
        imgHeight,
        img.opacity,
        8,
        img.loaded
      );
    });
  };

  // 使用惯性拖拽hook
  const dragInertia = useDragInertia(moveImages);

  const checkImageAt = (clientX: number, clientY: number) => {
    const canvas = canvasRef.current;
    if (!canvas) return;

    // 停止任何正在进行的拖拽惯性动画
    dragInertia.stopInertia();

    // 如果已经有选中的图片，开始取消选中动画
    if (selectedImage) {
      animatingImageRef.current?.startDeselectAnimation(selectedImage);
      return;
    }

    // 将 viewport 坐标转换为相对 canvas 坐标（如果 canvas 没铺满整个视窗）
    const rect = canvas.getBoundingClientRect();
    const x = clientX - rect.left;
    const y = clientY - rect.top;

    const hit = imgDataRef.current.find(
      (img) =>
        x >= img.x &&
        x < img.x + imgWidth &&
        y >= img.y &&
        y < img.y + imgHeight
    );
    if (hit && hit.loaded) {
      animatingImageRef.current?.startSelectAnimation(hit);
    }
  };

  const handleMouseDown: React.MouseEventHandler<HTMLCanvasElement> = (e) => {
    // 如果正在动画中，禁用交互
    if (animatingImageRef.current?.isAnimating()) return;

    dragStartPosRef.current = { x: e.clientX, y: e.clientY };
    hasMovedRef.current = false; // 重置移动状态
    dragInertia.startDrag(e.clientX, e.clientY);
  };

  const handleMouseUp: React.MouseEventHandler<HTMLCanvasElement> = (e) => {
    dragInertia.endDrag();
    // 如果正在动画中，禁用交互
    if (animatingImageRef.current?.isAnimating()) return;
  };

  const handleMouseLeave: React.MouseEventHandler<HTMLCanvasElement> = () => {
    dragInertia.endDrag();
  };

  const handleMouseMove: React.MouseEventHandler<HTMLCanvasElement> = (e) => {
    // 如果正在动画中，禁用交互
    if (animatingImageRef.current?.isAnimating()) return;

    // 更新移动状态（用于判断是否真正拖拽）
    if (dragStartPosRef.current) {
      const deltaX = e.clientX - dragStartPosRef.current.x;
      const deltaY = e.clientY - dragStartPosRef.current.y;
      const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);

      // 如果移动距离超过5px，认为是真正的拖拽
      if (distance > 5) {
        hasMovedRef.current = true;
      }
    }

    const result = dragInertia.updateDrag(e.clientX, e.clientY);
    if (result) {
      moveImages(result.dx, result.dy);
    }
  };

  const handleWheel: React.WheelEventHandler<HTMLCanvasElement> = (e) => {
    // 如果正在动画中，禁用交互
    if (animatingImageRef.current?.isAnimating()) return;
    const deltaY = -e.deltaY;
    const deltaX = -e.deltaX;
    moveImages(deltaX, deltaY);
  };

  // 触摸事件处理 - 开始触摸
  const handleTouchStart: React.TouchEventHandler<HTMLCanvasElement> = (e) => {
    // 如果正在动画中，禁用交互
    if (animatingImageRef.current?.isAnimating()) return;

    dragStartPosRef.current = {
      x: e.touches[0].clientX,
      y: e.touches[0].clientY,
    };
    hasMovedRef.current = false; // 重置移动状态
    dragInertia.startDrag(e.touches[0].clientX, e.touches[0].clientY);
  };

  // 触摸事件处理 - 触摸移动
  const handleTouchMove: React.TouchEventHandler<HTMLCanvasElement> = (e) => {
    // 如果正在动画中，禁用交互
    if (animatingImageRef.current?.isAnimating()) return;

    // 更新移动状态（用于判断是否真正拖拽）
    if (dragStartPosRef.current) {
      const deltaX = e.touches[0].clientX - dragStartPosRef.current.x;
      const deltaY = e.touches[0].clientY - dragStartPosRef.current.y;
      const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);

      // 如果移动距离超过5px，认为是真正的拖拽
      if (distance > 5) {
        hasMovedRef.current = true;
      }
    }

    const result = dragInertia.updateDrag(
      e.touches[0].clientX,
      e.touches[0].clientY
    );
    if (result) {
      moveImages(result.dx, result.dy);
    }
  };

  // 触摸事件处理 - 触摸结束
  const handleTouchEnd: React.TouchEventHandler<HTMLCanvasElement> = (e) => {
    dragInertia.endDrag();
    // 如果正在动画中，禁用交互
    if (animatingImageRef.current?.isAnimating()) return;
  };

  // 触摸事件处理 - 触摸取消
  const handleTouchCancel: React.TouchEventHandler<HTMLCanvasElement> = () => {
    dragInertia.endDrag();
  };

  // 点击事件处理
  const handleClick: React.MouseEventHandler<HTMLCanvasElement> = (e) => {
    // 如果正在动画中，禁用交互
    if (animatingImageRef.current?.isAnimating()) return;

    // 如果发生了真正的拖拽，不触发点击
    if (hasMovedRef.current) {
      return;
    }

    // 只有在没有真正拖拽的情况下才处理点击
    checkImageAt(e.clientX, e.clientY);
  };

  return (
    <div className="w-screen h-screen overflow-hidden">
      {/* 动画组件 */}
      <AnimatingGameImage
        ref={animatingImageRef}
        selectedImage={selectedImage}
        imgWidth={imgWidth}
        imgHeight={imgHeight}
        canvasRef={canvasRef}
        animationFrameRef={animationFrameRef}
        imgDataRef={imgDataRef}
        drawAll={drawAllFlush}
        setSelectedImage={setSelectedImage}
      />

      <canvas
        ref={canvasRef}
        className="w-screen h-screen overflow-hidden cursor-pointer absolute touch-action-none"
        onClick={handleClick}
        onWheel={handleWheel}
        onMouseDown={handleMouseDown}
        onMouseUp={handleMouseUp}
        onMouseLeave={handleMouseLeave}
        onMouseMove={handleMouseMove}
        onTouchStart={handleTouchStart}
        onTouchMove={handleTouchMove}
        onTouchEnd={handleTouchEnd}
        onTouchCancel={handleTouchCancel}
      />
    </div>
  );
}
